package com.example.vehiclefabric.config;

import io.grpc.ManagedChannel;
import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hyperledger.fabric.client.CallOption;
import org.hyperledger.fabric.client.Contract;
import org.hyperledger.fabric.client.Gateway;
import org.hyperledger.fabric.client.Network;
import org.hyperledger.fabric.client.identity.Identities;
import org.hyperledger.fabric.client.identity.Signers;
import org.hyperledger.fabric.client.identity.X509Identity;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

/**
 * @name: GatewayConfig
 * @description: 获取证书和密钥，配置网关以连接至区块链网络。
 * @author: Lulu Zhao
 **/
@Configuration
@AllArgsConstructor
@Slf4j
public class GatewayConfig {

    final Properties properties;

    /**
     * @name: gateway
     * @description: 读取证书和密钥，配置网关并返回网关对象。
     * @params: []
     * @return: org.hyperledger.fabric.client.Gateway
     * @author: Lulu Zhao
     */
    @Bean
    public Gateway gateway() throws Exception {

        BufferedReader certificateReader = Files.newBufferedReader(Paths.get(properties.getCertificatePath()), StandardCharsets.UTF_8);

        X509Certificate certificate = Identities.readX509Certificate(certificateReader);

        BufferedReader privateKeyReader = Files.newBufferedReader(Paths.get(properties.getPrivateKeyPath()), StandardCharsets.UTF_8);

        PrivateKey privateKey = Identities.readPrivateKey(privateKeyReader);

        Gateway gateway = Gateway.newInstance()
                .identity(new X509Identity((properties.getMspId()), certificate))
                .signer(Signers.newPrivateKeySigner(privateKey))
                .connection(newGrpcConnection())
                .evaluateOptions(CallOption.deadlineAfter(5, TimeUnit.SECONDS))
                .endorseOptions(CallOption.deadlineAfter(15, TimeUnit.SECONDS))
                .submitOptions(CallOption.deadlineAfter(5, TimeUnit.SECONDS))
                .commitStatusOptions(CallOption.deadlineAfter(1, TimeUnit.MINUTES))
                .connect();

        log.info("Connected to Fabric Gateway {}", gateway);

        return gateway;
    }

    /**
     * @name: newGrpcConnection
     * @description: 创建grpc连接。
     * @params: []
     * @return: io.grpc.ManagedChannel
     * @author: Lulu Zhao
     */
    private ManagedChannel newGrpcConnection() throws IOException, CertificateException {

        Reader tlsCertReader = Files.newBufferedReader(Paths.get(properties.getTlsCertPath()));

        X509Certificate tlsCert = Identities.readX509Certificate(tlsCertReader);

        return NettyChannelBuilder.forTarget("172.27.220.146:7780")
                .sslContext(GrpcSslContexts.forClient().trustManager(tlsCert).build())
                .overrideAuthority("p1.bc1.example.com")
                .build();
    }

    /**
     * @name: network
     * @description: 通过网关对象获得网络对象。
     * @params: [gateway]
     * @return: org.hyperledger.fabric.client.Network
     * @author: Lulu Zhao
     */
    @Bean
    public Network network(Gateway gateway) {
        return gateway.getNetwork(properties.getChannel());
    }

    /**
     * @name: simpleContract
     * @description: 通过网络对象获取智能合约。
     * @params: [network]
     * @return: org.hyperledger.fabric.client.Contract
     * @author: Lulu Zhao
     */
    @Bean
    public Contract simpleContract(Network network) {
        return network.getContract("simple");
    }

    /**
     * @name: vehccContract
     * @description: 通过网络对象获取智能合约。
     * @params: [network]
     * @return: org.hyperledger.fabric.client.Contract
     * @author: Lulu Zhao
     */
    @Bean
    public Contract vehccContract(Network network) {
        return network.getContract("vehcc");
    }

    /**
     * @name: chaccContract
     * @description: 通过网络对象获取智能合约。
     * @params: [network]
     * @return: org.hyperledger.fabric.client.Contract
     * @author: Lulu Zhao
     */
    @Bean
    public Contract chaccContract(Network network) {
        return network.getContract("chacc");
    }
}
